﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SimpleGame.SpriteClasses;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using SimpleGame.Utils;
using Microsoft.Xna.Framework.Input;
using SimpleGameData.GameObjects;
using System.Diagnostics;

namespace SimpleGame.GameObjects
{
    public class Player
    {
        #region Fields

        // The animated sprite of the player
        private AnimatedSprite animatedSprite;

        // The area where the player is allowed to move. normally the screen boundaries should be the limits.
        // TODO Make values variable to game resolution instead of fixed values.
        private Rectangle playerAreaLimit = new Rectangle(
            0,
            0,
            1000,
            650);

        #endregion

        #region Constructor

        public Player(AnimatedSprite animatedSprite)
        {
            this.animatedSprite = animatedSprite;
        }

        #endregion

        #region Update Methods

        /// <summary>
        /// Handles all the keyboard input. Add all player keyboard controls here.
        /// </summary>
        private void HandleKeyboardInput()
        {
            float x;
            float y;
            if (InputHandler.IsKeyDown(Keys.D))
            {
                // move right
                x = animatedSprite.AnimatedSpriteData.Direction.X + 1f;
                y = animatedSprite.AnimatedSpriteData.Direction.Y;
                animatedSprite.AnimatedSpriteData.Direction = new Vector2(x, y);
            }
            if (InputHandler.IsKeyDown(Keys.A))
            {
                // move left
                x = animatedSprite.AnimatedSpriteData.Direction.X - 1f;
                y = animatedSprite.AnimatedSpriteData.Direction.Y;
                animatedSprite.AnimatedSpriteData.Direction = new Vector2(x, y);
            }
            if (InputHandler.IsKeyDown(Keys.S))
            {
                // move down
                x = animatedSprite.AnimatedSpriteData.Direction.X;
                y = animatedSprite.AnimatedSpriteData.Direction.Y + 1f;
                animatedSprite.AnimatedSpriteData.Direction = new Vector2(x, y);
            }
            if (InputHandler.IsKeyDown(Keys.W))
            {
                // move up
                x = animatedSprite.AnimatedSpriteData.Direction.X;
                y = animatedSprite.AnimatedSpriteData.Direction.Y - 1f;
                animatedSprite.AnimatedSpriteData.Direction = new Vector2(x, y);
            }
        }

        /// <summary>
        /// Calculates the rotation of the player sprite in relation to the mouse cursor.
        /// </summary>
        public void CalculateRotation()
        {
            // get mouselocation
            Vector2 aimLocation = new Vector2(
                InputHandler.GetMousePositionX(),
                InputHandler.GetMousePositionY());
            // calculate sprite rotation in relation to mouse cursor
            animatedSprite.AnimatedSpriteData.Rotation = (float)Math.Atan2(
                InputHandler.GetMousePositionY() - animatedSprite.SpriteCenterPosition.Y,
                InputHandler.GetMousePositionX() - animatedSprite.SpriteCenterPosition.X) + (float)Math.PI / 2f;
        }

        /// <summary>
        /// Limit the player movement to the screen.
        /// </summary>
        private void LimitPlayerMovement()
        {
            // x, y positions of the sprite
            float x = animatedSprite.AnimatedSpriteData.Position.X;
            float y = animatedSprite.AnimatedSpriteData.Position.Y;

            // check left screen boundary
            if (animatedSprite.AnimatedSpriteData.Position.X < playerAreaLimit.Left)
            {
                x = playerAreaLimit.X;
            }
            // check top screen boundary
            if (animatedSprite.AnimatedSpriteData.Position.Y < playerAreaLimit.Top)
            {
                y = playerAreaLimit.Y;
            }
            // check right screen boundary
            if (animatedSprite.AnimatedSpriteData.Position.X + animatedSprite.Width * animatedSprite.AnimatedSpriteData.Scale.X 
                > playerAreaLimit.Right)
            {
                x = playerAreaLimit.Right - animatedSprite.Width * animatedSprite.AnimatedSpriteData.Scale.X;
            }
            // check bottom screen boundary
            if (animatedSprite.AnimatedSpriteData.Position.Y + animatedSprite.Height * animatedSprite.AnimatedSpriteData.Scale.Y 
                > playerAreaLimit.Bottom)
            {
                y = playerAreaLimit.Bottom - animatedSprite.Height * animatedSprite.AnimatedSpriteData.Scale.Y;
            }

            // set position to new x, y coordinates
            animatedSprite.AnimatedSpriteData.Position = new Vector2(x, y);
        }

        public void Update(GameTime gameTime)
        {
            AnimatedSpriteData spriteData = animatedSprite.AnimatedSpriteData;

            // get the elapsed time since last update
            float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds;

            // update sprite and animation
            animatedSprite.Update(gameTime);

            // reset direction vector
            spriteData.Direction = Vector2.Zero;

            // handle keyboard input and sets the direction vector if player is moved
            // by pressing a key.
            HandleKeyboardInput();

            // if direction vector is zero stop animation else normalize vector
            // to prevent faster diagonal movement and updae the position
            // based on the direction vector, velocity and the elapsed time
            // and start the animation of the animated sprite
            if (animatedSprite.AnimatedSpriteData.Direction != Vector2.Zero)
            {
                animatedSprite.IsAnimating = true;
                spriteData.Direction.Normalize();
                spriteData.Position += spriteData.Direction * spriteData.Velocity * elapsed;
            }
            else
            {
                animatedSprite.IsAnimating = false;
            }

            // calculates player facing mouse cursor
            CalculateRotation();

            // limit player movement to the screen
            LimitPlayerMovement();

            animatedSprite.AnimatedSpriteData = spriteData;
        }

        #endregion

        #region Draw Method

        public void Draw(SpriteBatch spriteBatch)
        {
            animatedSprite.Draw(spriteBatch);
        }

        #endregion
    }
}
